package com.eddie.jdbc.dao.impl;

import cn.hutool.core.util.StrUtil;
import com.eddie.jdbc.dao.BaseDao;
import com.eddie.jdbc.utils.MysqlConnectionUtil;
import lombok.SneakyThrows;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.sql.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author Eddie
 */
public class BaseDaoImpl<T> implements BaseDao<T> {
    public Class<?> gclass;
    public Connection conn = MysqlConnectionUtil.getConnection();
    public String simpleName;

    public BaseDaoImpl() {
        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
        gclass = (Class<?>) pt.getActualTypeArguments()[0];
        //将类名的Entity去掉，使用工具将驼峰命名法的属性名更改为带下划线（nick_name）
        simpleName = StrUtil.toUnderlineCase(gclass.getSimpleName().substring(0, gclass.getSimpleName().length() - 6));
    }


    @SneakyThrows
    @Override
    public T queryById(int id) {
        String sql = "select *from %s where id=?".formatted(simpleName);
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setObject(1, id);
        ResultSet rs = ps.executeQuery();
        // 实例化对象
        T t;
        try {
            t = (T) gclass.getDeclaredConstructor().newInstance();
            if (rs.next()) {
                getFilelds(rs, t);
            }
            return t;
        } catch (InstantiationException | InvocationTargetException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    @SneakyThrows
    @Override
    public List<T> queryAll() {
        String sql = "select *from %s".formatted(simpleName);
        PreparedStatement ps = conn.prepareStatement(sql);
        ResultSet rs = ps.executeQuery();
        // 实例化对象
        T t;
        try {
            List<T> data = new ArrayList<>();
            while (rs.next()) {
                t = (T) gclass.getDeclaredConstructor().newInstance();
                getFilelds(rs, t);
                data.add(t);
            }
            return data;
        } catch (InstantiationException | InvocationTargetException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    @SneakyThrows
    protected void getFilelds(ResultSet rs, T t) {
        Field[] df = gclass.getDeclaredFields();
        for (Field f : df) {
            String name = StrUtil.toUnderlineCase(f.getName());
            // 拿到属性的值
            Object value = rs.getObject(name);
            if (value == null) {
                continue;
            }
            // 拿到setter方法
            String setter = "set" + f.getName().substring(0, 1).toUpperCase() + f.getName().substring(1);
            // 获得对象的属性
            //如果从数据库获取时间类型，在这里反射调用set方法会出现异常，所以判断而去设置为data类型
            if (isValidDateTime(value.toString())) {
                Method method = gclass.getMethod(setter, value.getClass());
                method.invoke(t, Timestamp.valueOf(value.toString()));
                continue;
            }
            Method method = gclass.getMethod(setter, value.getClass());
            method.invoke(t, value);
        }
    }

    /**
     * 判断字符串是否为日期
     *
     * @param str 字符串
     * @return 是否为日期
     */
    public static boolean isValidDateTime(String str) {
        boolean convertSuccess = true;
        // 指定日期格式为四位年/两位月份/两位日期，注意yyyy/MM/dd区分大小写；
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        try {
            // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
            format.setLenient(false);
            format.parse(str);
        } catch (ParseException e) {
            /*如果throw java.text.ParseException或者NullPointerException，就说明格式不对*/
            convertSuccess = false;
        }
        return convertSuccess;
    }

    @Override
    public int queryCount() {
        return 0;
    }

    @Override
    public void insert(T t) {

    }

    @Override
    public void delete(int id) {

    }

    @SneakyThrows
    @Override
    public void update(T t) {
        // 获得类对象
        Class<?> class1 = t.getClass();
        String tableName = class1.getSimpleName();
        String getName = null;
        // 获得成员属性
        Field[] df = class1.getDeclaredFields();
        // 拼接sql语句
        // update User set id=?,uname=?,upwd=?,money=? where id=?
        StringBuilder sql = new StringBuilder("update " + tableName + " set ");
        for (int i = 0; i < df.length; i++) {
            Field field = df[i];
            getName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);

            sql.append(field.getName()).append("=?");
            if (i < df.length - 1) {
                sql.append(",");
            } else {
                sql.append(" where id=?");
            }
        }
        // update User set id=?,uname=?,upwd=?,money=? where id=?
        // 填充占位符
        PreparedStatement ps = conn.prepareStatement(sql.toString());
        // 存放条件表达式 即id,数组下标第一
        String where;
        for (int i = 0; i < df.length; i++) {
            Field field = df[i];
            getName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
            // 存放条件表达式 即id,数组下标第0位,填充第length+1位占位符
            try {
                if (i == 0) {
                    where = getName;
                    // 反射调用getId方法并把值拼接到最后一位

                    ps.setObject(df.length + 1, class1.getDeclaredMethod(where).invoke(t));

                }
                Method method = class1.getDeclaredMethod(getName);

                ps.setObject(i + 1, method.invoke(t));
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
        int executeUpdate = ps.executeUpdate();
        System.out.println(sql);
    }

}